﻿using Microsoft.Practices.Unity.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text;

namespace Artech.Core.Wcf
{
    public class ContextSender: IClientMessageFormatter
    {
        private HeaderNameResolver resolver;
        public string HeaderName { get; private set; }
        public string Namespace { get; private set;}
        public IClientMessageFormatter InnerMessageFormatter{get; private set;}

        public ContextSender(string headerName, string ns, IClientMessageFormatter innerMessageFormatter)
        {
            Guard.ArgumentNotNullOrEmpty(headerName, "headerName");
            Guard.ArgumentNotNullOrEmpty(ns, "ns");
            Guard.ArgumentNotNull(innerMessageFormatter, "innerMessageFormatter");

            this.HeaderName = headerName;
            this.Namespace = ns;
            this.InnerMessageFormatter = innerMessageFormatter;
            this.resolver = new HeaderNameResolver(ns);
        }

        protected virtual void SendContextItems(ContextItem[] items, ref Message request)
        {
            Guard.ArgumentNotNull(items, "items");

            if (request.Version.Envelope == EnvelopeVersion.Soap11 || request.Version.Envelope == EnvelopeVersion.Soap12)
            {
                MessageHeader<ContextItem[]> header = new MessageHeader<ContextItem[]>(items);
                request.Headers.Add(header.GetUntypedHeader(this.HeaderName, this.Namespace));
            }
            else
            {
                HttpRequestMessageProperty requestProperty = request.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
                if (null == requestProperty)
                {
                    requestProperty = new HttpRequestMessageProperty();
                    request.Properties.Add(HttpRequestMessageProperty.Name, requestProperty);
                }
                foreach (ContextItem item in items)
                {
                    requestProperty.Headers.Add(resolver.GetHeaderName(item.Key), item.Value.ToString());
                }
            }
        }

        public object DeserializeReply(Message message, object[] parameters)
        {
            return this.InnerMessageFormatter.DeserializeReply(message, parameters);
        }

        public Message SerializeRequest(MessageVersion messageVersion, object[] parameters)
        {
            ContextItem[] contextItems = ApplicationContext.Current.Provider.GetContextItems().ToArray();
            contextItems = contextItems.Where(item=>!item.IsLocal).ToArray();
            Message request = this.InnerMessageFormatter.SerializeRequest(messageVersion, parameters);
            this.SendContextItems(contextItems,ref request);
            MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue);
            request.Close();
            return buffer.CreateMessage();
        }
    }
}